// Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use log::trace;
use maestro_derive::MsgTag;
use ohmw_codegen::msg_def::{BaseType, MsgDef, MsgDefMap};
use ohmw_derive::{Decode, Encode};

use crate::system::SYSTEM_HANDLES;

#[derive(Clone, Encode, Decode)]
pub struct MsgDefInfo {
    pub node: String,
    pub msg_type: String,
    pub name: String,
    pub is_const: bool,
    pub const_value: String,
    pub is_array: bool,
    pub array_size: u32,
}

#[derive(Encode, Decode, MsgTag)]
#[msg_tag(case = "snake_case")]
pub struct QueryMsgDefineRet {
    pub msg_name: String,
    pub success: String,
    pub msg_defs: Vec<MsgDefInfo>,
}

impl MsgDefInfo {
    fn from_msg_def(msg_defs_map: &MsgDefMap, msg_def: &MsgDef) -> Vec<Self> {
        let mut msg_defs = Vec::new();
        for field in msg_def.fields.iter() {
            let (node, msg_type) = field.field_type.to_sep_strings();
            msg_defs.push(MsgDefInfo {
                node: node.unwrap_or(
                    msg_defs_map.find_msg_def_by_msg_name(&msg_type)
                        .map(|(pkg_name, _)| pkg_name.to_string())
                        .unwrap_or_else(|| "raw".to_string())
                ),
                msg_type,
                name: field.field_name.clone(),
                is_const: false,
                const_value: "".to_string(),
                is_array: field.field_type.is_array,
                array_size: field.field_type.array_size.unwrap_or(0),
            });
        }
        msg_defs
    }
}

pub async fn query_msg_define(msg_name: &str) -> QueryMsgDefineRet {
    trace!("query_msg_define: msg_name={}", msg_name);

    if !SYSTEM_HANDLES.lock().await.ensure_msg_defs_scanned().await {
        return QueryMsgDefineRet {
            msg_name: msg_name.to_string(),
            success: "scan msg defs failed".to_string(),
            msg_defs: vec![],
        };
    }

    let base_type = BaseType::from_string(msg_name.to_string());
    let msg_defs_map = &SYSTEM_HANDLES.lock().await.msg_defs;
    match msg_defs_map.find_msg_def(&base_type) {
        Some(msg_def) => QueryMsgDefineRet {
            msg_name: base_type.string,
            success: "ok".to_string(),
            msg_defs: MsgDefInfo::from_msg_def(msg_defs_map, msg_def),
        },
        None => QueryMsgDefineRet {
            msg_name: base_type.string,
            success: "msg def not found".to_string(),
            msg_defs: vec![],
        },
    }
}
